package com.kusej.dbdocexport.utils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yangkx
 * @Description 适用于LocalDateTime LocalDate LocalTime
 * @date 2021/3/19 18:50
 */
public class DateTimeUtils {

    private DateTimeUtils(){

    }

    public static final LocalDate EXCEL_BEGIN_DATE = LocalDate.of(1900,1,1);

    public static final String DB_DATE_FORMAT = "yyyyMMdd";
    public static final String DB_TIME_FORMAT = "HHmmss";
    public static final String DB_DATE_TIME_FORMAT = "yyyyMMdd HHmmss";
    public static final String DB_DATE_TIME_NO_BLANK_FORMAT = "yyyyMMddHHmmss";
    public static final String WEB_DATE_FORMAT = "yyyy-MM-dd";
    public static final String WEB_TIME_FORMAT = "HH:mm:ss";
    public static final String WEB_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String CN_DATE_FORMAT = "yyyy年MM月dd日";
    public static final String CN_DATE_TIME_FORMAT = "yyyy年MM月dd日 HH时mm分ss秒";


    public static final DateTimeFormatter DB_DATE_FORMATTER = DateTimeFormatter.ofPattern(DB_DATE_FORMAT);
    public static final DateTimeFormatter DB_TIME_FORMATTER = DateTimeFormatter.ofPattern(DB_TIME_FORMAT);
    public static final DateTimeFormatter DB_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DB_DATE_TIME_FORMAT);
    public static final DateTimeFormatter DB_DATE_TIME_NO_BLANK_FORMATTER = DateTimeFormatter.ofPattern(DB_DATE_TIME_NO_BLANK_FORMAT);
    public static final DateTimeFormatter WEB_DATE_FORMATTER = DateTimeFormatter.ofPattern(WEB_DATE_FORMAT);
    public static final DateTimeFormatter WEB_TIME_FORMATTER = DateTimeFormatter.ofPattern(WEB_TIME_FORMAT);
    public static final DateTimeFormatter WEB_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(WEB_DATE_TIME_FORMAT);
    public static final DateTimeFormatter CN_DATE_FORMATTER = DateTimeFormatter.ofPattern(CN_DATE_FORMAT);
    public static final DateTimeFormatter CN_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(CN_DATE_TIME_FORMAT);


    private static final Map<String,DateTimeFormatter> DATE_TIME_FORMATTER_MAP;

    private static final String[] DEFAULT_DATE_FORMAT;
    private static final String[] DEFAULT_TIME_FORMAT;
    private static final String[] DEFAULT_DATE_TIME_FORMAT;

    static {
        DEFAULT_DATE_FORMAT = new String[]{DB_DATE_FORMAT,WEB_DATE_FORMAT};
        DEFAULT_TIME_FORMAT = new String[]{DB_TIME_FORMAT,WEB_TIME_FORMAT};
        DEFAULT_DATE_TIME_FORMAT = new String[]{DB_DATE_TIME_FORMAT,WEB_DATE_TIME_FORMAT,DB_DATE_TIME_NO_BLANK_FORMAT};
        DATE_TIME_FORMATTER_MAP = new HashMap<>(8);
        DATE_TIME_FORMATTER_MAP.put(DB_DATE_FORMAT,DB_DATE_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(DB_TIME_FORMAT,DB_TIME_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(DB_DATE_TIME_FORMAT,DB_DATE_TIME_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(WEB_DATE_FORMAT,WEB_DATE_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(WEB_TIME_FORMAT,WEB_TIME_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(WEB_DATE_TIME_FORMAT,WEB_DATE_TIME_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(DB_DATE_TIME_NO_BLANK_FORMAT,DB_DATE_TIME_NO_BLANK_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(CN_DATE_FORMAT,CN_DATE_FORMATTER);
        DATE_TIME_FORMATTER_MAP.put(CN_DATE_TIME_FORMAT,CN_DATE_TIME_FORMATTER);
    }
    /**
     * 取yyyyMMdd类型当前时间
     * @return
     */
    public static Integer getDbDateNow() {
        return Integer.valueOf(DB_DATE_FORMATTER.format(LocalDate.now()));
    }

    /**
     * 取当前时间 yyyyMMdd HHmmss
     * @return
     */
    public static String getDbDateTimeNow(){
        return DB_DATE_TIME_FORMATTER.format(LocalDateTime.now());
    }

    /**
     * 取yyyy-MM-dd类型当前时间
     * @return
     */
    public static String getWebDateNow() {
        return LocalDate.now().toString();
    }

    /**
     * 取当前时间 yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String getWebDateTimeNow(){
        return WEB_DATE_TIME_FORMATTER.format(LocalDateTime.now());
    }

    /**
     * 转换字符串到日期
     * @param dateStr
     * @param pattern
     * @return
     */
    public static LocalDate parse2LocalDate(String dateStr,String ...pattern){
        if (dateStr == null || dateStr.isEmpty()){
            return null;
        }
        String[] formatPattern;
        if (pattern.length == 0){
            formatPattern = DEFAULT_DATE_FORMAT;
        }else {
            formatPattern = pattern;
        }
        LocalDate localDate;
        for (String onePattern : formatPattern) {
            try {
                DateTimeFormatter formatter = DATE_TIME_FORMATTER_MAP.get(onePattern);
                if (formatter == null){
                    formatter = DateTimeFormatter.ofPattern(onePattern);
                }
                localDate = LocalDate.parse(dateStr,formatter);
                return localDate;
            }catch (Exception e){
                continue;
            }
        }
        return null;
    }
    /**
     * 转换字符串到时间
     * @param timeStr
     * @param pattern
     * @return
     */
    public static LocalTime parse2LocalTime(String timeStr,String ...pattern){
        if (timeStr == null || timeStr.isEmpty()){
            return null;
        }
        String[] formatPattern;
        if (pattern.length == 0){
            formatPattern = DEFAULT_TIME_FORMAT;
        }else {
            formatPattern = pattern;
        }
        LocalTime localTime;
        for (String onePattern : formatPattern) {
            try {
                DateTimeFormatter formatter = DATE_TIME_FORMATTER_MAP.get(onePattern);
                if (formatter == null){
                    formatter = DateTimeFormatter.ofPattern(onePattern);
                }
                localTime = LocalTime.parse(timeStr,formatter);
                return localTime;
            }catch (Exception e){
                continue;
            }
        }
        return null;
    }
    /**
     * 转换你字符串到日期时间
     * @param dateStr
     * @param pattern
     * @return
     */
    public static LocalDateTime parse2LocalDateTime(String dateStr,String ...pattern){
        if (dateStr == null || dateStr.isEmpty()){
            return null;
        }
        String[] formatPattern;
        if (pattern.length == 0){
            formatPattern = DEFAULT_DATE_TIME_FORMAT;
        }else {
            formatPattern = pattern;
        }
        LocalDateTime localDateTime;
        for (String onePattern : formatPattern) {
            try {
                DateTimeFormatter formatter = DATE_TIME_FORMATTER_MAP.get(onePattern);
                if (formatter == null){
                    formatter = DateTimeFormatter.ofPattern(onePattern);
                }
                localDateTime = LocalDateTime.parse(dateStr,formatter);
                return localDateTime;
            }catch (Exception e){
                continue;
            }
        }
        return null;
    }

    /**
     * 格式化日期 yyyy-MM-dd
     * @param localDate
     * @return
     */
    public static String format2WebDate(LocalDate localDate){
        if (localDate == null){
            return null;
        }
        return localDate.toString();
    }
    /**
     * 格式化时间 HH:mm:ss
     * @param localTime
     * @return
     */
    public static String format2WebTime(LocalTime localTime){
        if (localTime == null){
            return null;
        }
        return WEB_TIME_FORMATTER.format(localTime);
    }

    public static String format2DbDate(LocalDate localDate){
        if (localDate == null){
            return "";
        }
        return DB_DATE_FORMATTER.format(localDate);
    }
    public static String format2CNDate(LocalDate localDate){
        if (localDate == null){
            return "";
        }
        return CN_DATE_FORMATTER.format(localDate);
    }

    public static Integer format2IntegerDbDate(LocalDate localDate){
        if (localDate == null){
            return null;
        }
        return Integer.valueOf(DB_DATE_FORMATTER.format(localDate));
    }
    /**
     * 数据库日期需要为0
     * @param localDate
     * @return
     */
    public static int format2IntDbDate(LocalDate localDate){
        if (localDate == null){
            return 0;
        }
        return Integer.parseInt(DB_DATE_FORMATTER.format(localDate));
    }

    public static int format2IntDbTime(LocalTime localTime){
        if (localTime == null){
            return 0;
        }
        return Integer.parseInt(DB_TIME_FORMATTER.format(localTime));
    }
    public static int format2IntDbDate(LocalDateTime localDateTime){
        if (localDateTime == null){
            return 0;
        }
        return Integer.parseInt(DB_DATE_FORMATTER.format(localDateTime));
    }

    public static int format2IntDbTime(LocalDateTime localDateTime){
        if (localDateTime == null){
            return 0;
        }
        return Integer.parseInt(DB_TIME_FORMATTER.format(localDateTime));
    }


    public static String formatDateTime(LocalDateTime dateTime, String pattern){
        if (dateTime == null || pattern == null){
            return "";
        }
        DateTimeFormatter formatter = DATE_TIME_FORMATTER_MAP.get(pattern);
        if (formatter != null){
            return formatter.format(dateTime);
        }
        formatter = DateTimeFormatter.ofPattern(pattern);
        DATE_TIME_FORMATTER_MAP.putIfAbsent(pattern, formatter);
        return formatter.format(dateTime);
    }

    /**
     * 格式化日期 yyyy-MM-dd HH:mm:ss
     * @param localDateTime
     * @return
     */
    public static String format2WebDateTime(LocalDateTime localDateTime){
        if (localDateTime == null){
            return null;
        }
        return WEB_DATE_TIME_FORMATTER.format(localDateTime);
    }
    /**
     * yyyyMMdd-->yyyy-MM-dd
     * @param dbDate
     * @return dbDate为null时会return null
     */
    public static String formatDbDate2Web(String dbDate){
        if (dbDate == null || dbDate.isEmpty()){
            return null;
        }
        return WEB_DATE_FORMATTER.format(parseDbDate(dbDate));
    }
    /**
     * yyyy-MM-dd-->yyyyMMdd
     * @param webDate
     * @return webDate为null时会return null
     */
    public static String formatWebDate2Db(String webDate){
        if (webDate == null || webDate.isEmpty()){
            return null;
        }
        return DB_DATE_FORMATTER.format(parseWebDate(webDate));
    }
    /**
     * Date类型给前端转换
     * @param date
     * @return
     */
    public static String formatDateType2Web(Date date){
        if (date == null) {
            return "";
        }
        return WEB_DATE_TIME_FORMATTER.format(oldDate2NewDateTime(date));
    }
    /**
     * 补全8位的HsDate类型 yyyyMMdd
     * @param hsDate
     * @return
     */
    public static String formatHsDate(Integer hsDate){
        return String.format("%08d", hsDate);
    }

    /**
     * 补全六位的HsTime类型 HHmmss
     * @param hsTime
     * @return
     */
    public static String formatHsTime(Integer hsTime){
        return String.format("%06d", hsTime);
    }
    /**
     * 补全六位的HsTime类型 HHmmss
     * @param hsTime
     * @return
     */
    public static String formatHsTime(String hsTime){
        StringBuilder stringBuilder = new StringBuilder(hsTime);
        for (int i = 0; i < (6-hsTime.length()); i++) {
            stringBuilder.insert(0,"0");
        }
        return stringBuilder.toString();
    }

    /**
     * 获取当月的起始日期
     * @param localDate
     * @return
     */
    public static LocalDate getBeginDateThisMonth(LocalDate localDate){
        if (localDate == null){
            return null;
        }
        return localDate.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取当月的最后日期
     * @param localDate
     * @return
     */
    public static LocalDate getEndDateThisMonth(LocalDate localDate){
        if (localDate == null){
            return null;
        }
        return localDate.with(TemporalAdjusters.lastDayOfMonth());
    }

    /**
     * 取时间戳
     * @param localDateTime
     * @return
     */
    public static Long getTimeStamp(LocalDateTime localDateTime){
        if (localDateTime == null){
            return null;
        }
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }
    /**
     * 取时间戳
     * @param localDate
     * @return
     */
    public static Long getTimeStamp(LocalDate localDate){
        if (localDate == null){
            return null;
        }
        return localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 数据库日期转换时间戳
     * @param currDate
     * @return
     */
    public static Long getTimeStampDb(String currDate){
        return getTimeStamp(LocalDate.parse(currDate,DB_DATE_FORMATTER));
    }
    /**
     * 数据库日期转换时间戳
     * @param currDate
     * @return
     */
    public static Long getTimeStampDb(Integer currDate){
        if (currDate == null){
            return null;
        }
        return getTimeStamp(LocalDate.parse(formatHsDate(currDate),DB_DATE_FORMATTER));
    }
    /**
     * 数据库日期时间转换时间戳
     * @param currDate
     * @return
     */
    public static Long getTimeStampDb(String currDate,String currTime){
        if (currDate == null){
            return null;
        }
        if (currTime == null){
            return getTimeStampDb(currDate);
        }
        LocalDate localDate = LocalDate.parse(currDate, DB_DATE_FORMATTER);
        LocalTime localTime = LocalTime.parse(formatHsTime(currTime), DB_TIME_FORMATTER);
        return getTimeStamp(localDate.atTime(localTime));
    }
    /**
     * 数据库日期时间转换时间戳
     * @param currDate
     * @return
     */
    public static Long getTimeStampDb(Integer currDate,Integer currTime){
        if (currDate == null){
            return null;
        }
        if (currTime == null){
            return getTimeStampDb(formatHsDate(currDate));
        }
        return getTimeStampDb(formatHsDate(currDate),formatHsTime(currTime));
    }
    /**
     * web日期转换时间戳
     * @param webDate
     * @return
     */
    public static Long getTimeStampWeb(String webDate){
        if (webDate.length()==WEB_DATE_FORMAT.length()){
            return getTimeStamp(LocalDate.parse(webDate,WEB_DATE_FORMATTER));
        }
        if (webDate.length()==WEB_DATE_TIME_FORMAT.length()){
            return getTimeStamp(LocalDate.parse(webDate,WEB_DATE_TIME_FORMATTER));
        }
        return null;
    }

    /**
     * web日期时间转JAVA类
     * @param webDateTime
     * @return
     */
    public static LocalDateTime parseWebDateTime(String webDateTime){
        if (webDateTime == null || webDateTime.isEmpty()){
            return null;
        }
        return LocalDateTime.parse(webDateTime,WEB_DATE_TIME_FORMATTER);
    }
    /**
     * web日期转JAVA类
     * @param webDate
     * @return
     */
    public static LocalDate parseWebDate(String webDate){
        if (webDate == null || webDate.isEmpty()){
            return null;
        }
        return LocalDate.parse(webDate,WEB_DATE_FORMATTER);
    }
    /**
     * web时间转JAVA类
     * @param webTime
     * @return
     */
    public static LocalTime parseWebTime(String webTime){
        if (webTime == null || webTime.isEmpty()){
            return null;
        }
        return LocalTime.parse(webTime,WEB_TIME_FORMATTER);
    }
    /**
     * 数据库日期转JAVA类
     * @param currDate
     * @return
     */
    public static LocalDate parseDbDate(Integer currDate){
        if (currDate == null || currDate == 0 || currDate.toString().length()<8){
            return null;
        }
        return LocalDate.parse(currDate.toString(),DB_DATE_FORMATTER);
    }
    /**
     * 数据库日期转JAVA类
     * @param currTime
     * @return
     */
    public static LocalTime parseDbTime(Integer currTime){
        if (currTime == null || currTime==0){
            return null;
        }
        return LocalTime.parse(formatHsTime(currTime),DB_TIME_FORMATTER);
    }
    /**
     * 数据库日期转JAVA类
     * @param currDate
     * @return
     */
    public static LocalDate parseDbDate(String currDate){
        if (currDate == null || currDate.isEmpty() || "0".equals(currDate)){
            return null;
        }
        return LocalDate.parse(currDate,DB_DATE_FORMATTER);
    }
    /**
     * 数据库日期转JAVA类
     * @param currTime
     * @return
     */
    public static LocalTime parseDbTime(String currTime){
        if (currTime == null || currTime.isEmpty()){
            return null;
        }
        return LocalTime.parse(formatHsTime(currTime),DB_TIME_FORMATTER);
    }
    /**
     * 数据库日期+时间转JAVA类
     * @param currDate
     * @param currTime
     * @return
     */
    public static LocalDateTime parseDbDateTime(Integer currDate,Integer currTime){
        if (currDate == null || currDate == 0){
            return null;
        }
        if (currTime == null){
            LocalDate localDate = LocalDate.parse(formatHsDate(currDate), DB_DATE_FORMATTER);
            return localDate.atStartOfDay();
        }
        return parseDbDateTime(formatHsDate(currDate),formatHsTime(currTime));
    }
    /**
     * 数据库日期+时间转JAVA类
     * @param currDate
     * @param currTime
     * @return
     */
    public static LocalDateTime parseDbDateTime(String currDate,String currTime){
        LocalDate localDate = LocalDate.parse(currDate, DB_DATE_FORMATTER);
        LocalTime localTime = LocalTime.parse(formatHsTime(currTime), DB_TIME_FORMATTER);
        return localDate.atTime(localTime);
    }

    /**
     * 老jdk日期转新jdk8的日期
     * @param date
     * @return
     */
    public static LocalDateTime oldDate2NewDateTime(Date date){
        if (date == null){
            return null;
        }
        return date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }
    /**
     * 老jdk日期转新jdk8的日期
     * @param date
     * @return
     */
    public static LocalDate oldDate2NewDate(Date date){
        if (date == null){
            return null;
        }
        return date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    /**
     * 转换Excel的特殊日期到LocalDate
     * @param daysNum
     * @return 1900/01/01+(daysNum-2)
     */
    public static LocalDate parseExcelDate(Integer daysNum){
        if (daysNum==null || daysNum<=1){
            return null;
        }
        return EXCEL_BEGIN_DATE.plusDays(daysNum-2);
    }

    /**
     * 解决LocalDateTime.of不能处理null的问题
     * @param date
     * @param time
     * @return
     */
    public static LocalDateTime nullableOf(LocalDate date,LocalTime time){
        if (date == null){
            return null;
        }
        if (time == null){
            return LocalDateTime.of(date,LocalTime.MIN);
        }
        return LocalDateTime.of(date,time);
    }
}
